﻿using System;
using System.Collections.Generic;
using System.Diagnostics;

using Gonte.Reflection;

namespace Gonte.Web.Json
{
    /// <summary>
    /// The grid metadata to create dynamic grids from the server
    /// </summary>
    public class JsonGridMetaData
    {
        #region Properties

        /// <summary>
        /// The property that provides an ID for the record (optional)
        /// </summary>
        public string idProperty { get; set; }

        /// <summary>
        /// The property that contains the array of records
        /// </summary>
        public string root { get; set; }

        /// <summary>
        /// The property that contains the number of records (optional)
        /// </summary>
        public string totalProperty { get; set; }

        /// <summary>
        /// The property that contains the success flag
        /// </summary>
        public string successProperty { get; set; }

        /// <summary>
        /// The information about the columns of the grid
        /// </summary>
        public JsonGridColumnInfo[] fields { get; set; }

        public JsonGridSortInfo sortInfo { get; set; } 

        #endregion

        #region Methods

        public void Populate(Type type)
        {
            root = "gridData";
            successProperty = "success";
            fields = PopulateFields(type);
        }
        
        #endregion

        /// <summary>
        /// Populates the field metadata with the information from the type
        /// </summary>
        /// <param name="type">The type to populate the metadata from</param>
        /// <returns>The array of field information</returns>
        private JsonGridColumnInfo[] PopulateFields(Type type)
        {
            List<JsonGridColumnInfo> fieldList = new List<JsonGridColumnInfo>();

            TypeTraversal typeTraversal = new TypeTraversal();
            typeTraversal.Property = (traversal, property) =>
            {
                Type propertyType = property.PropertyType;

                if (propertyType.IsPrimitive())
                {
                    AddFieldInfo(fieldList, property.Name, propertyType);
                }
                else // It is either a collection of values or a complex object
                {
                    if (propertyType.IsCollection()) // Extract the element type
                    {
                        Type itemType = propertyType.GetItemType();

                        if (itemType.IsPrimitive())
                        {
                            AddFieldInfo(fieldList, property.Name, itemType, true);
                        }
                        else
                        {
                            AddFieldInfo(fieldList, property.Name, itemType, true);
                            //HandleComplexObject(property);
                        }
                    }
                    else
                    {
                        AddFieldInfo(fieldList, property.Name, propertyType);
                        //HandleComplexObject(property);
                    }
                }
            };

            typeTraversal.Traverse(type);

            JsonGridColumnInfo[] fields = new JsonGridColumnInfo[fieldList.Count];
            fieldList.CopyTo(fields);

            return fields;
        }

        private void AddFieldInfo(List<JsonGridColumnInfo> fieldList, string propertyName, Type propertyType, bool isCollection = false)
        {
            JsonGridColumnInfo fieldInfo = new JsonGridColumnInfo
            {
                name = propertyName,
                dataIndex = propertyName,
                header = propertyName, // TODO: Create a provider to do the localization
                type = GetMappedType(/* provider, */ propertyType)
            };

            if (isCollection)
            {
                fieldInfo.editor = new StringCollectionEditor
                {
                    transform = fieldInfo.dataIndex
                };
            }

            fieldList.Add(fieldInfo);
        }

        private static void HandleComplexObject(System.Reflection.PropertyInfo property)
        {
            JsonFormResponse.TraceSource.TraceEvent(TraceEventType.Warning, 0,
                "Property of name: '{0}' in object of type '{1}' is a complex object. Ignoring it",
                property.Name,
                property.DeclaringType.FullName);
        }

        /// <summary>
        /// Maps the type to the javascript type
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private string GetMappedType(Type type)
        {
            switch (type.FullName)
            {
                case "System.String": return "string";
                case "System.Int32": return "int";
                case "System.Boolean": return "bool";
                case "System.DateTime": return "date";
            }

            return "string";

            //throw new ArgumentException(string.Format("Unknown type to map: '{0}'", type.FullName));
        }
    }
}
